/**
 * @(#)ProxyHostUtils.java 2016年7月21日
 * Copyright(C) 2015 ZHEXIN IT CO.,LTD. All rights reserved.
 */
package com.zhexinit.proxy.util;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.jsbd.boss.common.redis.RedisClient;
import org.jsbd.boss.util.CacheKey;
import org.jsbd.boss.util.DateUtil;
import org.jsbd.boss.util.JsonConvertUtils;
import org.jsbd.boss.util.PropertiesUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSON;
import com.zhexinit.proxy.domain.ProxyHost;
import com.zhexinit.proxy.domain.SDKProxyHost;

/**
 * 获取代理地址的工具类
 * 
 * @author <a href="mailto:zhaihuilin@zhexinit.com" >翟惠林</a>
 * @version 1.0.0
 */
@Service
public class ProxyHostUtils {
	public static final Logger LOGGER = LoggerFactory.getLogger(ProxyHostUtils.class);

	/**
	 * 代理服务器WEB管理主机地址
	 */
	public static final String HTTP_PROXY_WEB_ADDRESS = PropertiesUtil.getValue("http.proxy.web.host", "10.252.223.236:7900");
	/**
	 * 通过代理服务器WEB管理主机获取直接代理服务的URL
	 */
	public static final String HTTP_PROXY_BY_PROVINCE_AND_IMSI_URL = "http://" + HTTP_PROXY_WEB_ADDRESS + "/getProxyHostByProvinceAndImsi?provinceId=${id}&imsi=${imsi}";

	/**
	 * 通过SDK代理服务器代理请求的服务器地址
	 */
	public static final String SDK_PROXY_SERVER = PropertiesUtil.getValue("sdk.proxy.server", "10.252.208.13:14402");

	/**
	 * SDK代理服务器查询的请求地址，用于固定代理服务器地址；
	 */
	public static final String SDK_PROXY_QUERY_URL = "http://" + SDK_PROXY_SERVER + "/query?IMSI=${imsi}&provinceId=${provinceId}";

	/**
	 * 0、表示使用SDK代理服务器 1、表示使用VPS代理服务器
	 */
	public static final int PROXY_FLAG = PropertiesUtil.getInt("proxy.flag", 0);

	/**
	 * 是否内网，默认是内网，外网开发测试请设置成false
	 */
	public static final boolean IS_INTERNAL = PropertiesUtil.getBoolean("isInternal", true);

	/**
	 * 是否测试，测试时使用本地代理服务器，localhost 8888
	 */

	public static final Boolean TEST_PROXY = PropertiesUtil.getBoolean("proxy.test", false);

	private static final Map<String, String> INTERNAL_MAPPING = new HashMap<String, String>();

	private static RedisClient redisClient = (RedisClient) SpringServiceUtils.getService("redisClient");
	private static final int ONE_DAY = 60 * 60 * 24;
	private static final int RETRY_FOR_GET_PROXY_HOST = 5;

	static {
		INTERNAL_MAPPING.put("10.252.208.13", "120.26.6.201");
		INTERNAL_MAPPING.put("10.252.213.153", "120.26.4.251");
		INTERNAL_MAPPING.put("10.252.211.242", "120.26.3.132");
		INTERNAL_MAPPING.put("10.1.0.5", "121.196.197.17");
		INTERNAL_MAPPING.put("10.10.10.12", "121.43.190.223");
	}

	/**
	 * 
	 * 获取代理服务器地址，需要代理服务器WEB端新开接口，可以使用IMSI和provinceId一起获取IP；
	 * 
	 * @author <a href="mailto:zhaihuilin@zhexinit.com" >翟惠林</a>
	 * @param imsi
	 * @param provinceId
	 * @param ipLimitCount
	 *            一个IP可以使用的用户数
	 * @param bizType
	 *            业务类型
	 * @return
	 */
	@SuppressWarnings({ "unchecked" })
	public static ProxyHost getProxyHost(String imsi, String provinceId, int ipLimitCount, String bizType) {
		if (TEST_PROXY) {
			ProxyHost testProxyHost = new ProxyHost();
			testProxyHost.setAddress("127.0.0.1");
			testProxyHost.setPort(8888);
			testProxyHost.setIp("127.0.0.1:8888");
			return testProxyHost;
		}
		ProxyHost proxyHost = null;
		if (PROXY_FLAG == 0) {
			String makeImsi = imsi;// ip上限
			String resultExistMakeImsi = existMakeImsi(imsi, bizType);
			// 判断是否造过imsi
			if (resultExistMakeImsi != null) {
				makeImsi = resultExistMakeImsi;
				proxyHost = getProxyHostFromSDKProxy(makeImsi, provinceId);
				LOGGER.info("imsi[{}]改造后", makeImsi);
				return proxyHost;
			}
			for (int i = 0; i < RETRY_FOR_GET_PROXY_HOST; i++) {
				proxyHost = getProxyHostFromSDKProxy(makeImsi, provinceId);
				if (ipLimitCount < 0) {
					LOGGER.info("没有限制");
					return proxyHost;
				}
				String ipConnect = proxyHost.getIp();
				if (StringUtils.isBlank(ipConnect)) {
					LOGGER.info("IPconnect is null");
					continue;
				}
				String ip = ipConnect.split(":")[0];
				// 创造imsi key
				String proxyHostIpMakeKey = CacheKey.PROXY_HOST_IP_MAKE_MISI + bizType + "_" + makeImsi + "_" + DateUtil.getCurrentDateStr();
				String proxyHostIpUsedKey = CacheKey.PROXY_HOST_IP_USED_BY_IMSI + bizType + "_" + ip + "_" + imsi + "_" + DateUtil.getCurrentDateStr();
				String proxyHostIpUsed = (String) redisClient.get(proxyHostIpUsedKey);
				if (proxyHostIpUsed == null) {
					String proxyHostIpCounterKey = CacheKey.PROXY_HOST_IP_COUNTER + bizType + "_" + ip + "_" + DateUtil.getCurrentDateStr();
					Long counter = redisClient.getLong(proxyHostIpCounterKey);
					if (counter != null && counter >= 30) {
						makeImsi = makeImsi + i;
						LOGGER.info("IPconnect[{}]大于[{}]次,重试[{}] ", new Object[] { ip, 30, i });
						continue;
					}
					redisClient.put(proxyHostIpUsedKey, imsi, 86400);
					counter = redisClient.incrementBy(proxyHostIpCounterKey, 1, ONE_DAY);
					LOGGER.info("IPconnect[{}]使用了[{}]次,第[{}]次重试 ", new Object[] { ip, counter, i });
					if (!makeImsi.equals(imsi)) {
						redisClient.put(proxyHostIpMakeKey, makeImsi, 86400);
					}
				}
				return proxyHost;
			}

		} else {
			proxyHost = getVpsProxy(imsi, provinceId, ipLimitCount, bizType);
			if (proxyHost != null) {
				return proxyHost;
			}
		}

		return proxyHost;

	}

	private static ProxyHost getProxyHostFromSDKProxy(String imsi, String provinceId) {
		String url = SDK_PROXY_QUERY_URL;
		url = url.replaceAll("\\$\\{imsi\\}", imsi);
		url = url.replaceAll("\\$\\{provinceId\\}", provinceId);
		CloseableHttpClient client = HttpClientBuilder.create().build();
		HttpGet get = new HttpGet(url);
		String result = null;
		ProxyHost proxyHost = null;
		try {
			HttpResponse response = client.execute(get);
			ByteArrayOutputStream outstream = new ByteArrayOutputStream();
			response.getEntity().writeTo(outstream);
			result = outstream.toString();
			LOGGER.debug(result);
			if (StringUtils.isNotBlank(result)) {
				LOGGER.debug("result [{}]", result);

				SDKProxyHost sdkProxyHost = JSON.parseObject(result, SDKProxyHost.class);
				LOGGER.debug("sdk proxy host [{}]", sdkProxyHost);
				String host = sdkProxyHost.getProxyservice().getHost();
				proxyHost = new ProxyHost();
				proxyHost.setPort(sdkProxyHost.getProxyservice().getPort());
				// 如果是外网,替换对照地址
				if (!IS_INTERNAL) {
					host = INTERNAL_MAPPING.get(host);
				}
				proxyHost.setAddress(host);
				proxyHost.setIp(sdkProxyHost.getProxyinfo().getIpConnect());
				LOGGER.debug("proxyHost [{}]", proxyHost);
			}
			return proxyHost;
		} catch (ClientProtocolException e) {
			LOGGER.error("URL {}", new Object[] { url, e });
		} catch (IOException e) {
			LOGGER.error("URL {}", new Object[] { url, e });
		} catch (Exception e) {
			LOGGER.error("URL [{}],result[{}]", new Object[] { url, result, e });
		} finally {
			get.releaseConnection();
		}
		return null;
	}

	/**
	 * 通过VPS代理服务器代理
	 * 
	 * @author <a href="mailto:zhaihuilin@zhexinit.com" >翟惠林</a>
	 * @param imsi
	 * @param provinceId
	 * @return
	 */
	private static ProxyHost getProxyHostFromVPSProxy(String imsi, String provinceId) {
		String url = HTTP_PROXY_BY_PROVINCE_AND_IMSI_URL;
		url = url.replaceAll("\\$\\{imsi\\}", imsi);
		url = url.replaceAll("\\$\\{id\\}", provinceId);
		CloseableHttpClient client = HttpClientBuilder.create().build();
		HttpGet get = new HttpGet(url);
		String result = null;
		ProxyHost proxyHost = null;
		try {
			HttpResponse response = client.execute(get);
			ByteArrayOutputStream outstream = new ByteArrayOutputStream();
			response.getEntity().writeTo(outstream);
			result = outstream.toString();
			LOGGER.debug(result);
			if (StringUtils.isNotBlank(result)) {
				proxyHost = (ProxyHost) JsonConvertUtils.jsonToBean(result, ProxyHost.class);
			}
			return proxyHost;
		} catch (ClientProtocolException e) {
			LOGGER.error("URL {}", new Object[] { url, e });
		} catch (IOException e) {
			LOGGER.error("URL {}", new Object[] { url, e });
		} catch (Exception e) {
			LOGGER.error("URL [{}],result[{}]", new Object[] { url, result, e });
		} finally {
			get.releaseConnection();
		}
		return null;
	}

	/**
	 * @author sund
	 * @param imsi
	 * @param bizType
	 * @des 判断是否造过imsi
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static String existMakeImsi(String imsi, String bizType) {
		String result = null;
		String existImsi = null;
		for (int j = 0; j < RETRY_FOR_GET_PROXY_HOST; j++) {
			existImsi = imsi + j;
			String proxyHostIpMakeKey = CacheKey.PROXY_HOST_IP_MAKE_MISI + bizType + "_" + existImsi + "_" + DateUtil.getCurrentDateStr();// 创造imsi
																																			// key
			String proxyHostIpMaked = (String) redisClient.get(proxyHostIpMakeKey);
			if (proxyHostIpMaked != null) {
				result = proxyHostIpMaked;
				break;
			}
		}
		return result;
	}

	/**
	 * @author sund
	 * @param imsi
	 * @param provinceId
	 * @param ipLimitCount
	 *            一个ip最大用户数
	 * @param bizType
	 * @des vps长连接ip分散
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static ProxyHost getVpsProxy(String imsi, String provinceId, int ipLimitCount, String bizType) {

		ProxyHost proxyHost = null;
		String makeImsi = imsi;// ip上限
		String resultExistMakeImsi = existMakeImsi(imsi, bizType);
		// 判断是否造过imsi
		if (resultExistMakeImsi != null) {
			makeImsi = resultExistMakeImsi;
			proxyHost = getProxyHostFromVPSProxy(makeImsi, provinceId);
			LOGGER.info("imsi[{}]改造后", makeImsi);
			return proxyHost;
		}
		for (int i = 0; i < RETRY_FOR_GET_PROXY_HOST; i++) {
			proxyHost = getProxyHostFromVPSProxy(makeImsi, provinceId);
			if (ipLimitCount < 0) {
				LOGGER.info("没有限制");
				return proxyHost;
			}
			String ip = proxyHost.getAddress();
			// 创造imsi key
			String proxyHostIpMakeKey = CacheKey.PROXY_HOST_IP_MAKE_MISI + bizType + "_" + makeImsi + "_" + DateUtil.getCurrentDateStr();
			String proxyHostIpUsedKey = CacheKey.PROXY_HOST_IP_USED_BY_IMSI + bizType + "_" + ip + "_" + makeImsi + "_" + DateUtil.getCurrentDateStr();
			String proxyHostIpUsed = (String) redisClient.get(proxyHostIpUsedKey);
			if (proxyHostIpUsed == null) {
				String proxyHostIpCounterKey = CacheKey.PROXY_HOST_IP_COUNTER + bizType + "_" + ip + "_" + DateUtil.getCurrentDateStr();
				Long counter = redisClient.getLong(proxyHostIpCounterKey);
				if (counter != null && counter >= ipLimitCount && i < RETRY_FOR_GET_PROXY_HOST - 1) {
					makeImsi = makeImsi + i;
					LOGGER.info("IPconnect[{}]大于[{}]次,重试[{}] ", new Object[] { ip, ipLimitCount, i });
					continue;
				}
				redisClient.put(proxyHostIpUsedKey, makeImsi, 86400);
				counter = redisClient.incrementBy(proxyHostIpCounterKey, 1, ONE_DAY);
				LOGGER.info("IPconnect[{}]使用了[{}]次,第[{}]次重试 ", new Object[] { ip, counter, i });
			}
			if (!makeImsi.equals(imsi)) {
				redisClient.put(proxyHostIpMakeKey, makeImsi, 86400);
			}
			return proxyHost;
		}
		return proxyHost;
	}

	//
	// private static ProxyHost getTestVPSProxy(String imsi, String provinceId)
	// {
	// ProxyHost proxyHost = new ProxyHost();
	// proxyHost.setIp("192.168.0,1");
	// proxyHost.setAddress("33333");
	// return proxyHost;
	// }
}
